package com.changgou.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.changgou.entity.Result;
import com.changgou.feign.SkuFeign;
import com.changgou.search.service.SkuSearchService;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** 
* @Author: 少迪
* @Date: Created in 2019-08-09 11:31
* @Description:  
* @Version: 1.0
*/ 

@Service
public class SkuSearchServiceImpl implements SkuSearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private RedisTemplate redisTemplate;

    private final String brandKey = "BRAND_LIST";
    private final String specKey = "SPEC_LIST";

    @Override
    public void importSkuList(List<Map> skuList) {

        //1.创建批处理对象
        BulkRequest bulkRequest = new BulkRequest();
        //2.构建批处理对象
        for (Map sku : skuList) {
            IndexRequest indexRequest = new IndexRequest("sku");
            indexRequest.id(String.valueOf(sku.get("id")));
            Map spec = JSON.parseObject(String.valueOf(sku.get("spec")), Map.class);
            sku.put("spec", spec);
            indexRequest.source(sku);
            bulkRequest.add(indexRequest);
        }
        //3.执行批量处理

        try {
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            System.out.println("执行批量处理结果code：" + bulkResponse.status().getStatus());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Autowired
    private SkuFeign skuFeign;

    @Override
    public void importSkuListBySpuId(String spuId) {
        //1. 获取需要导入的数据
        Map searchMap = new HashMap(2);
        searchMap.put("spuId", spuId);
        searchMap.put("status", "1");
        Result skuResult = skuFeign.findList(searchMap);
        if (skuResult.isFlag()) {
            List<Map> skuList = (List<Map>) skuResult.getData();
            if (skuList != null) {
                importSkuList(skuList);
            }
        } else {
            System.out.println("远程调用失败");
        }

    }

    /**
     * 将所有sku导入到es中
     */
    @Override
    public void importAll() {
        Map map = new HashMap(2);
        map.put("status", "1");
        map.put("idDelete", "0");
        int pageNo = 1;
        while (true) {
            System.out.println("导入第" + pageNo + "页");
            Result result = skuFeign.findPage(map, pageNo, 1000);
            List<Map> skuList = (List<Map>) ((Map) result.getData()).get("rows");
            if (skuList.size() == 0) {
                break;
            }
            importSkuList(skuList);
            pageNo++;
        }
    }


    /**
     * 商品查询
     *
     * @param searchMap keywords 查询关键字
     *                  category 商品分类
     *                  brand 品牌
     *                  spec.*  规格
     *                  price 价格 0-500
     *                  pageNo 页码
     *                  pageSize 每页记录数
     *                  sort 排序字段
     *                  sortOrder 排序规则（升序或降序）
     * @return rows 商品查询结果
     * categoryList  商品分类列表
     * brandList  品牌列表
     * specList 规格列表
     */
    @Override
    public Map search(Map<String, String> searchMap) {
        //DSL
        //1.封装查询请求
        SearchRequest searchRequest = new SearchRequest();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //1.1 条件查询 query
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //1.1.1 关键字查询
        if (searchMap.get("keywords") != null) {
            MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", searchMap.get("keywords"));
            boolQueryBuilder.must(matchQueryBuilder);
        }

        //1.1.2 商品分类过滤
        if (searchMap.get("category") != null) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("categoryName", searchMap.get("category"));
            boolQueryBuilder.filter(termQueryBuilder);
        }

        //1.1.3 品牌过滤
        if (searchMap.get("brand") != null) {
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", searchMap.get("brand"));
            boolQueryBuilder.filter(termQueryBuilder);
        }

        //1.1.4 规格过滤
        for (String key : searchMap.keySet()) {
            if (key.startsWith("spec.")) {
                TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(key + ".keyword", searchMap.get(key));
                boolQueryBuilder.filter(termQueryBuilder);
            }
        }

        //1.1.5 价格过滤
        if (searchMap.get("price") != null) {
            //1000-1500
            String[] price = searchMap.get("price").split("-");
            if (!"0".equals(price[0])) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").gte(price[0] + "00");
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
            if (!"*".equals(price[1])) {
                RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").lte(price[1] + "00");
                boolQueryBuilder.filter(rangeQueryBuilder);
            }
        }

        searchSourceBuilder.query(boolQueryBuilder);

        //1.2 高亮查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name").preTags("<font style='color:red'>").postTags("</font>");
        searchSourceBuilder.highlighter(highlightBuilder);

        //1.3 分组查询(聚合查询)
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("sku_category").field("categoryName");
        ;
        searchSourceBuilder.aggregation(termsAggregationBuilder);

        //1.4 分页查询
        if (searchMap.get("pageNo") == null) {
            searchMap.put("pageNo", "1");
        }
        if (searchMap.get("pageSize") == null) {
            searchMap.put("pageSize", "30");
        }

        //页码
        Integer pageNo = Integer.valueOf(searchMap.get("pageNo"));
        //页大小
        Integer pageSize = Integer.valueOf(searchMap.get("pageSize"));
        int fromIndex = (pageNo - 1) * pageSize;
        searchSourceBuilder.from(fromIndex);
        searchSourceBuilder.size(pageSize);

        //1.5 排序
        if (searchMap.get("sort") == null) {
            searchMap.put("sort", "");
        }
        if (searchMap.get("sortOrder") == null) {
            searchMap.put("sortOrder", "DESC");
        }
        if (!"".equals(searchMap.get("sort"))) {
            searchSourceBuilder.sort(searchMap.get("sort"), SortOrder.valueOf(searchMap.get("sortOrder")));
        }

        searchRequest.source(searchSourceBuilder);

        //2.封装查询结果
        Map resultMap = new HashMap(5);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHits searchHits = searchResponse.getHits();

            //2.1 商品列表
            SearchHit[] hits = searchHits.getHits();
            List<Map> skuList = new ArrayList<>();
            for (SearchHit hit : hits) {
                Map<String, Object> skuMap = hit.getSourceAsMap();
                //处理高亮
                if (searchMap.get("keywords") != null) {
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    HighlightField name = highlightFields.get("name");
                    Text[] fragments = name.fragments();
                    skuMap.put("name", fragments[0].toString());
                }
                skuList.add(skuMap);
            }
            resultMap.put("rows", skuList);

            //2.2 商品分类列表
            Aggregations aggregations = searchResponse.getAggregations();
            Map<String, Aggregation> aggrMap = aggregations.getAsMap();
            Terms terms = (Terms) aggrMap.get("sku_category");
            List<? extends Terms.Bucket> buckets = terms.getBuckets();
            //分类列表
            List<String> categoryList = new ArrayList<>();
            for (Terms.Bucket bucket : buckets) {
                categoryList.add(bucket.getKeyAsString());
            }
            resultMap.put("categoryList", categoryList);

            //2.3 品牌和规格列表查询
            String categoryName = "";
            if (categoryList.size() > 0) {
                categoryName = categoryList.get(0);
            }
            //2.3.1 品牌列表查询
            List<Map> brandList = (List<Map>) redisTemplate.boundHashOps(brandKey).get(categoryName);
            if (brandList != null) {
                resultMap.put("brandList", brandList);
            } else {
                resultMap.put("brandList", new ArrayList<>());
            }
            //2.3.2 规格列表查询
            List<Map> specList = (List<Map>) redisTemplate.boundHashOps(specKey).get(categoryName);
            if (specList != null) {
                resultMap.put("specList", specList);
            } else {
                resultMap.put("specList", new ArrayList<>());
            }

            // 2.4 页码计算
            TotalHits totalHits = searchHits.getTotalHits();
            System.out.println("记录数：" + totalHits.value);
            //计算总页数
            long totalPages = (totalHits.value%pageSize==0)?(totalHits.value/pageSize):(totalHits.value/pageSize+1);
            resultMap.put( "totalPages",totalPages );

        } catch (IOException e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    @Override
    public void deleteSkuListBySpuId(String spuId) {

        DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest("sku");
        TermQueryBuilder termQuery = QueryBuilders.termQuery("spuId", spuId);
        deleteByQueryRequest.setQuery(termQuery);
        try {
            restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
